
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "cuPrintf.cu"

#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

cudaError_t helloWorld();

__global__ void helloKernel()
{
	int i = threadIdx.x;
	cuPrintf("Hello From: %d\n", i);
}

int main()
{

	// Add vectors in parallel.
	cudaError_t cudaStatus = helloWorld();
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "addWithCuda failed!");
		return 1;
	}

	// cudaDeviceReset must be called before exiting in order for profiling and
	// tracing tools such as Nsight and Visual Profiler to show complete traces.
	cudaStatus = cudaDeviceReset();
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaDeviceReset failed!");
		return 1;
	}
	char none[80];
	cin >> none;
	return 0;
}

// Helper function for using CUDA to add vectors in parallel.
cudaError_t helloWorld()
{
	cudaError_t cudaStatus;

	int deviceId;
	string deviceName;
	int deviceCount = 0;
	cudaError_t error_id = cudaGetDeviceCount(&deviceCount);

	if (error_id != cudaSuccess)
	{
		printf("cudaGetDeviceCount returned %d\n-> %s\n", (int)error_id, cudaGetErrorString(error_id));
		exit(EXIT_FAILURE);
	}

	// This function call returns 0 if there are no CUDA capable devices.
	if (deviceCount == 0)
	{
		printf("There are no available device(s) that support CUDA\n");
	}
	else
	{
		printf("Detected %d CUDA Capable device(s)\n", deviceCount);
	}

	int major = 0;
	int minor = 0;
	for (int dev = 0; dev < deviceCount; ++dev)
	{
		cudaDeviceProp deviceProp;
		cudaGetDeviceProperties(&deviceProp, dev);

		printf("\nDevice %d: \"%s\"\n", dev, deviceProp.name);
		if(deviceProp.major > major || (deviceProp.major == major && deviceProp.minor > minor))
		{
			major = deviceProp.major;
			minor = deviceProp.minor;
			deviceId = dev;
			deviceName = deviceProp.name;
		}
	}
	printf("\nCoosing your coolest CUDA device: %d: \"%s\" (highest compute capability)\n", deviceId, deviceName.c_str());
	// Choose which GPU to run on, change this on a multi-GPU system.
	cudaStatus = cudaSetDevice(deviceId);
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
		goto Error;
	}

	cudaPrintfInit();
	helloKernel<<< 2, 3 >>>();
	cudaPrintfDisplay(stdout, true);
	cudaPrintfEnd();

	// cudaDeviceSynchronize waits for the kernel to finish, and returns
	// any errors encountered during the launch.
	cudaStatus = cudaDeviceSynchronize();
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
		goto Error;
	}
Error:
	return cudaStatus;
}
